import { CSSProperties } from "react"
import { DynamicValue } from "./GDynamicValue"

export type IndexedObject<T> = { [key: string]: T }
export type ValueOf<T> = T[keyof T]
export type Omit<T, K> = Pick<T, Exclude<keyof T, K>>
export type Overwrite<T, U> = Omit<T, keyof U> & U
export type Mode = 'light' | 'dark'


type GStylesParams<T> = T extends (new (styles: infer R) => any) ? R : T;
export type DStyles = GStylesParams<typeof DynamicStyleSheet>

type Style = CSSProperties

type DynamicStyle<T extends Style> = { [Key in keyof T]: T[Key] | DynamicValue<T[Key]> }
type DynamicStyles<T> = { [P in keyof T]: DynamicStyle<Style> }

type NormalizeStyle<T> = T extends DynamicStyle<infer R> ? R : T
export type NormalizeStyles<T extends DynamicStyles<T>> = { [Key in keyof T]: NormalizeStyle<T[Key]> }

function parseStylesFor<T extends DynamicStyles<T>>(styles: T, mode: Mode): NormalizeStyles<T> {
	const newStyles: IndexedObject<IndexedObject<ValueOf<ValueOf<T>>>> = {}

	let containsDynamicValues = false

	for (const i in styles) {
		const style = styles[i]
		type Value = ValueOf<ValueOf<T>>
		const newStyle: IndexedObject<Value> = {}
		for (const j in style) {
			const value = style[j]

			if (value instanceof DynamicValue) {
				containsDynamicValues = true
				newStyle[j] = value[mode]
			} else {
				newStyle[j] = value as Value
			}
		}
		newStyles[i] = newStyle
	}

	if (!containsDynamicValues && process.env.NODE_ENV !== 'production') {
		console.warn(
			'A DynamicStyleSheet was used without any DynamicValues. Consider replacing with a regular StyleSheet.',
		)
	}

	return (newStyles as unknown) as NormalizeStyles<T>
}

export class DynamicStyleSheet<T extends DynamicStyles<T>> {
	public readonly dark: NormalizeStyles<T>
	public readonly light: NormalizeStyles<T>

	constructor(styles: T) {
		this.dark = parseStylesFor(styles, 'dark') as NormalizeStyles<T>
		this.light = parseStylesFor(styles, 'light') as NormalizeStyles<T>
	}
}
